/*
 * tree.h
 *
 *  Created on: Mar 3, 2011
 *      Author: tqlong
 */

#ifndef TREE_H_
#define TREE_H_

#include "data/pointset.h"
#include <iostream>

template<typename T>
class TreeNode
{
public:
  typedef std::vector<int>               iset_type;
  typedef PointSet<T>                    pset_type;
  typedef typename pset_type::vec_type   vec_type;
  typedef std::vector<TreeNode<T>*>      nodelist_type;
protected:
  pset_type& p_;      // point set
  iset_type& idx_;    // original index
  int lo_, hi_ex_;    // index range
  TreeNode* parent_;  // parent node
  nodelist_type children_;  // children nodes
public:
  /** Root constructor */
  TreeNode(pset_type& p, iset_type& idx)
    : p_(p), idx_(idx), lo_(0), hi_ex_(p.n()), parent_(NULL)
  {
    idx_ = iset_type(p_.n());
    for (int i = 0; i < p_.n(); i++) idx_[i] = i;
    assert(p.n() == (int) idx_.size());
//    std::cerr << "idx.size = " << idx_.size() << " p.n = " << p_.n() <<"\n"; std::cerr.flush();
  }
  /** Child constructor */
  TreeNode(TreeNode& parent, int lo, int hi_ex)
    : p_(parent.p_), idx_(parent.idx_), lo_(parent.lo_+lo), hi_ex_(parent.lo_+hi_ex), parent_(&parent){}
  /** Add a child node */
  void addChild(TreeNode& child) { children_.push_back(&child); }
  /** Basic information */
  int n_tree() const { return idx_.size(); }
  int n() const { return hi_ex_ - lo_; }
  int n_child() const { return children_.size(); }
  int dim() const { return p_.dim(); }
  /** Access methods */
  TreeNode* child(unsigned int i) const { assert(i < children_.size()); return children_[i]; }
  const vec_type& origPoint(int i) const { assert(i < n_tree()); return p_[idx_[i]]; }
  int idx(int i) const { assert(i < n()); return lo_+i; }
  const vec_type& point(int i) const { assert(i < n()); return origPoint(lo_+i); }
  void swapIndex(int i, int j) {
    assert(i < n() && j < n());
    int tmp = idx_[lo_+i]; idx_[lo_+i] = idx_[lo_+j]; idx_[lo_+j] = tmp;
  }
  double distance(int i, int j) {
    assert(i < n() && j < n());
    return arma::norm(this->point(i) - this->point(j), 2);
  }
  virtual void print() {}
};

#endif /* TREE_H_ */
